package com.ng.framework.view.desktop.table;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.text.DecimalFormat;
import java.util.Enumeration;

import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.table.TableColumn;

public class NGCustomTable extends JTable {
	
	private static final long serialVersionUID = -4998820836523301196L;
	
	private NGTableModel tableModel;
	private NGCustomTableHeader tableHeader;
	
	public NGCustomTable(Object[] columnNames) {
		this(columnNames, 0);
	}
	
	public NGCustomTable(Object[] columnNames, int numRows) {
		this(new NGTableModel(columnNames, numRows));
	}

	public NGCustomTable(NGTableModel tableModel) {
		super(tableModel);
		
		this.tableModel = tableModel;
		this.tableHeader = new NGCustomTableHeader(this.getColumnModel());

//		this.setUI(new NGTableUI());
		
		this.setDefaultRenderer(Object.class, new NGTableCellRenderer());
		this.setDefaultRenderer(Boolean.class, new NGCheckBoxTableCellRenderer());
		
		this.setTableHeader(tableHeader);
	
		this.setCellSelectionEnabled(true);
		this.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
	}
	
	public void addRow(Object[] rowData) {
		tableModel.addRow(rowData);
	}
	
	public void setEditable(boolean editable) {
		for(int row = 0; row < this.getRowCount(); row ++) {
			for(int column = 0; column < this.getColumnCount(); column++) {
				this.setCellEditable(row, column, editable);
			}
		}
	}
	
	public void setCellEditable(int row, int column, boolean editable) {
		tableModel.setCellEditable(row, column, editable);
	}
	
	public void setFractionColumn(int column) {
		tableModel.setFractionColumn(column, true);
		this.getColumnModel().getColumn(column).setCellEditor(new NGFractionCellEditor());
	}
	
	public boolean isFractionColumn(int column) {
		return tableModel.isFractionColumn(column);
	}
	
	public void setNumericColumn(int column, Class<? extends Number> clazz) {
		NGNumberCellEditor<?> numberCellEditor = null;

		if (clazz == Byte.class) {
			numberCellEditor = new NGNumberCellEditor<Byte>(Byte.class, new DecimalFormat("#"));
		} else if (clazz == Short.class) {
			numberCellEditor = new NGNumberCellEditor<Short>(Short.class, new DecimalFormat("#"));
		} else if (clazz == Integer.class) {
			numberCellEditor = new NGNumberCellEditor<Integer>(Integer.class, new DecimalFormat("#"));
		} else if (clazz == Long.class) {
			numberCellEditor = new NGNumberCellEditor<Long>(Long.class, new DecimalFormat("#"));
		} else if (clazz == Float.class) {
			numberCellEditor = new NGNumberCellEditor<Float>(Float.class, new DecimalFormat("0.00"));
		} else if (clazz == Double.class) {
			numberCellEditor = new NGNumberCellEditor<Double>(Double.class, new DecimalFormat("0.00"));
		}

		if(numberCellEditor != null) {
			this.getColumnModel().getColumn(column).setCellEditor(numberCellEditor);
		}
	}

	public void combine(int startingRow, int startingColumn, int rowCount, int columnCount) {
		NGCellAttributes cellAttributes = tableModel.getCellAttributes();
		
		int[] rows = new int[rowCount];
		for(int i = 0; i < rows.length; i++) {
			rows[i] = startingRow + i;
		}
		
		int[] columns = new int[columnCount];
		for(int i = 0; i < columns.length; i++) {
			columns[i] = startingColumn + i;
		}
		
		cellAttributes.combine(rows, columns);
	}
	
	public void setColumnGroup(String text, int startColumn, int endColumn) {
		NGColumnGroup columnGroup = new NGColumnGroup(text);
		
		for(int i = startColumn; i <= endColumn; i++) {
			columnGroup.add(this.getColumnModel().getColumn(i));
		}
		
		tableHeader.addColumnGroup(columnGroup);
	}
	
	public void setCellForeground(int row, int column, Color foreground) {
		tableModel.setCellForeground(row, column, foreground);
	}
	
	public void setCellBackground(int row, int column, Color background) {
		tableModel.setCellBackground(row, column, background);
	}
	
	public void setCellAlignment(int row, int column, Integer alignment) {
		tableModel.setCellAlignment(row, column, alignment);
	}

	public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
		Rectangle sRect = super.getCellRect(row, column, includeSpacing);
		if ((row < 0) || (column < 0) || (getRowCount() <= row)
				|| (this.getColumnCount() <= column)) {
			return sRect;
		}
		NGCellAttributes cellAtt = tableModel.getCellAttributes();
		if (!cellAtt.isVisible(row, column)) {
			int temp_row = row;
			int temp_column = column;
			row += cellAtt.getSpan(temp_row, temp_column)[NGCellAttributes.ROW];
			column += cellAtt.getSpan(temp_row, temp_column)[NGCellAttributes.COLUMN];
		}
		int[] n = cellAtt.getSpan(row, column);

		int index = 0;
		int columnMargin = this.getColumnModel().getColumnMargin();
		Rectangle cellFrame = new Rectangle();
//		int aCellHeight = rowHeight;
//		cellFrame.y = row * aCellHeight;
//		cellFrame.height = n[NGCellAttributes.ROW] * aCellHeight;
		
		int y = 0;
		for(int i = 0; i < row; i++) {
			y += getRowHeight(i);
		}
		cellFrame.y = y;
		
		int height = 0;
		for(int i = row; i < row + n[NGCellAttributes.ROW]; i++) {
			height += getRowHeight(i);
		}
		cellFrame.height = height;

		Enumeration<TableColumn> enumeration = this.getColumnModel().getColumns();
		while (enumeration.hasMoreElements()) {
			TableColumn aColumn = (TableColumn) enumeration.nextElement();
			cellFrame.width = aColumn.getWidth();
			if (index == column) {
				break;				
			}
			cellFrame.x += cellFrame.width;
			index++;
		}
		for (int i = 0; i < n[NGCellAttributes.COLUMN] - 1; i++) {
			TableColumn aColumn = (TableColumn) enumeration.nextElement();
			cellFrame.width += aColumn.getWidth() + columnMargin;
		}

		if (!includeSpacing) {
			Dimension spacing = this.getIntercellSpacing();
			cellFrame.setBounds(cellFrame.x + spacing.width / 2, cellFrame.y
					+ spacing.height / 2, cellFrame.width - spacing.width,
					cellFrame.height - spacing.height);
		}
		return cellFrame;
	}

	private int[] rowColumnAtPoint(Point point) {
		int[] retValue = { -1, -1 };
		//int row = point.y / (rowHeight + rowMargin);
		int row = super.rowAtPoint(point);
		if ((row < 0) || (getRowCount() <= row))
			return retValue;
		int column = this.getColumnModel().getColumnIndexAtX(point.x);

		NGCellAttributes cellAttributes = tableModel.getCellAttributes();

		if (cellAttributes.isVisible(row, column)) {
			retValue[NGCellAttributes.COLUMN] = column;
			retValue[NGCellAttributes.ROW] = row;
			return retValue;
		}
		
		retValue[NGCellAttributes.COLUMN] = column
				+ cellAttributes.getSpan(row, column)[NGCellAttributes.COLUMN];
		retValue[NGCellAttributes.ROW] = row
				+ cellAttributes.getSpan(row, column)[NGCellAttributes.ROW];
		return retValue;
	}

	public int rowAtPoint(Point point) {
		return this.rowColumnAtPoint(point)[NGCellAttributes.ROW];
	}

	public int columnAtPoint(Point point) {
		return this.rowColumnAtPoint(point)[NGCellAttributes.COLUMN];
	}

	public void columnSelectionChanged(ListSelectionEvent e) {
		this.repaint();
	}

	public void valueChanged(ListSelectionEvent e) {
		int firstIndex = e.getFirstIndex();
		int lastIndex = e.getLastIndex();
		if (firstIndex == -1 && lastIndex == -1) {
			this.repaint();
		}
		Rectangle dirtyRegion = this.getCellRect(firstIndex, 0, false);
		int numCoumns = getColumnCount();
		int index = firstIndex;
		for (int i = 0; i < numCoumns; i++) {
			dirtyRegion.add(getCellRect(index, i, false));
		}
		index = lastIndex;
		for (int i = 0; i < numCoumns; i++) {
			dirtyRegion.add(getCellRect(index, i, false));
		}
		this.repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width,
				dirtyRegion.height);
	}
	
}
